package com.ruoyi.common.core.config.mybatis.enhance;

import com.ruoyi.common.core.utils.StringUtils;
import lombok.Data;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 *
 * @author Cao.Yu
 * @date 2023-06-09 15:21
 */
@Data
public class LambdaResolve {

    /**
     * 方法名: resolve <br/>
     * 描述: 将Lambda方法引用 处理为数据库字段名 如:mybatis-plus效果 <br/>
     * 作者: Cao.Yu <br/>
     * 日期: Created in 2023/6/12 2:02 下午
     */
    public static <T, R> String resolve(SFunction<T, R> func) {
        String implMethodName = doFunction(func).getImplMethodName();
        return parseToUnderlineField(implMethodName);
    }

    /**
     * 方法名: parseToUnderlineField <br/>
     * 描述: 解析为下划线字段名 <br/>
     * 作者: Cao.Yu <br/>
     * 日期: Created in 2023/6/9 4:39 下午
     */
    public static String parseToUnderlineField(String implMethodName) {
        //String implMethodName = sl.getImplMethodName();
        String propertyName;
        // 方法名  get  set  is
        if (implMethodName.startsWith("get") || implMethodName.startsWith("set")) {
            propertyName = implMethodName.substring(3);
        } else if (implMethodName.startsWith("is")) {
            propertyName = implMethodName.substring(2);
        } else if (implMethodName.startsWith("lambda$")) {
            throw new IllegalArgumentException("SerializableFunction不能传递lambda表达式,只能使用方法引用");
        } else {
            throw new IllegalArgumentException(String.format("Error parsing property name '%s'. Didn't start with 'is', 'get' or 'set'.", implMethodName));
        }
        if (StringUtils.isEmpty(propertyName)) {
            throw new IllegalArgumentException(String.format("Error parsing property name '%s'. The property cannot be empty.", implMethodName));
        }
        return StringUtils.humpToUnderline(propertyName);
    }


    /**
     * 方法名: doFunction <br/>
     * 描述: 比起mybatis-plus更简单的得到SerializedLambda <br/>
     * 作者: Cao.YU <br/>
     * 日期: Created in 2023/6/9 4:02 下午
     */
    public static <T, R> SerializedLambda doFunction(SFunction<T, R> func) {
        Object sl = null;
        try {
            // 直接调用writeReplace
            Method writeReplace = func.getClass().getDeclaredMethod("writeReplace");
            writeReplace.setAccessible(true);
            //反射调用
            sl = writeReplace.invoke(func);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return (SerializedLambda) sl;
    }

    /**
     * 方法名: doConsume <br/>
     * 描述: 比起mybatis-plus更简单的得到SerializedLambda <br/>
     * 作者: Cao.Yu <br/>
     * 日期: Created in 2023/6/9 4:05 下午
     */
    public static <T> SerializedLambda doConsume(SConsumer<T> consumer) throws Exception {
        // 直接调用writeReplace
        Method writeReplace = consumer.getClass().getDeclaredMethod("writeReplace");
        writeReplace.setAccessible(true);
        //反射调用
        Object sl = writeReplace.invoke(consumer);
        return  (SerializedLambda) sl;
    }

}
